// Refactored by Fredrique Samuels (fredriquesamuels@gmail.com)

#ifndef SIGSLOT10_H__
#define SIGSLOT10_H__

#include "base.h"
#include <list>

namespace sigslot {

//========================================

class _connection_base10 {
public:
	virtual has_slots* getdest()=0;
};

//========================================

template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
		class arg4_type, class arg5_type, class arg6_type, class arg7_type,
		class arg8_type, class arg9_type, class arg10_type> class _connection10 :
	public _connection_base10 {
public:
	_connection10(
			dest_type* pobject,
			void (dest_type::*pmemfun)(arg1_type,arg2_type,arg3_type,arg4_type,arg5_type,arg6_type,arg7_type,arg8_type,arg9_type,arg10_type)) {
		m_pobject = pobject;
		m_pmemfun = pmemfun;
	}

	inline void emit(arg1_type arg1, arg2_type arg2, arg3_type arg3,
			arg4_type arg4, arg5_type arg5, arg6_type arg6, arg7_type arg7,
			arg8_type arg8, arg9_type arg9, arg10_type arg10) {
		(((dest_type*)getdest())->*m_pmemfun)(arg1, arg2, arg3, arg4, arg5,
				arg6, arg7, arg8, arg9, arg10);
	}

	inline virtual has_slots* getdest() {
		return m_pobject;
	}

private:
	dest_type* m_pobject;
	void (dest_type::*m_pmemfun)(arg1_type,arg2_type,arg3_type,arg4_type,arg5_type,arg6_type,arg7_type,arg8_type,arg9_type,arg10_type);
};

class _signal_base10 :public _signal_base {
public:

	_signal_base10() {

	}

	virtual ~_signal_base10() {

	}

	inline virtual void disconnect(has_slots* pclass)=0;

};

template<class arg1_type,class arg2_type,class arg3_type,class arg4_type,class arg5_type,class arg6_type,class arg7_type,class arg8_type,class arg9_type,class arg10_type>
class signal10:public _signal_base10 {
public:
	signal10() :_signal_base10() {

	}

	virtual ~signal10() {
		disconnect_all();
	}

	template<class desttype>
	inline void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,arg2_type,arg3_type,arg4_type,arg5_type,arg6_type,arg7_type,arg8_type,arg9_type,arg10_type))
	{
		_connection10<desttype,arg1_type,arg2_type,arg3_type,arg4_type,arg5_type,arg6_type,arg7_type,arg8_type,arg9_type,arg10_type>* conn =
		new _connection10<desttype,arg1_type,arg2_type,arg3_type,arg4_type,arg5_type,arg6_type,arg7_type,arg8_type,arg9_type,arg10_type>(pclass, pmemfun);
		m_connected_slots.push_back(conn);
		pclass->signal_connect(this);

	}

	inline void emit(arg1_type arg1,arg2_type arg2,arg3_type arg3,arg4_type arg4,arg5_type arg5,arg6_type arg6,arg7_type arg7,arg8_type arg8,arg9_type arg9,arg10_type arg10)
	{
		std::list<_connection_base10* >::const_iterator itNext, it =m_connected_slots.begin();
		std::list<_connection_base10* >::const_iterator itEnd = m_connected_slots.end();

			while(it != itEnd)
			{
				itNext = it;
				++itNext;
				
				conn_emit((*it)->getdest(),(*it),arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10);
				
				it = itNext;
			}
		}
	

	inline void disconnect(has_slots* pclass)
	{

		std::list<_connection_base10* >::iterator it = m_connected_slots.begin();
		std::list<_connection_base10* >::iterator itEnd = m_connected_slots.end();

		while(it != itEnd)
		{
			if((*it)->getdest() == pclass)
			{
				delete *it;
				m_connected_slots.erase(it);
				pclass->signal_disconnect(this);
				return;
			}

			++it;
		}
	}

	inline void disconnect_all()
	{
		std::list<_connection_base10* >::const_iterator it = m_connected_slots.begin();
		std::list<_connection_base10* >::const_iterator itEnd = m_connected_slots.end();

		while(it != itEnd)
		{
			(*it)->getdest()->signal_disconnect(this);
			delete *it;

			++it;
		}

		m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
	}
private:
	template<class desttype>
	void conn_emit(desttype* pclass,void* conn,arg1_type arg1,arg2_type arg2,arg3_type arg3,arg4_type arg4,arg5_type arg5,arg6_type arg6,arg7_type arg7,arg8_type arg8,arg9_type arg9,arg10_type arg10){
		((_connection10<desttype,arg1_type,arg2_type,arg3_type,arg4_type,arg5_type,arg6_type,arg7_type,arg8_type,arg9_type,arg10_type>*)conn)->emit(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10);
	}
	
	protected:
		std::list<_connection_base10* > m_connected_slots;

	};

}// namespace sigslot

#endif // SIGSLOT_H__

